#include "bsp_uart.h"
#include <stdio.h>
#include <string.h>

uint8_t Receive_Buff[BufferMaxLength];   /* 接收数据缓冲区 */
uint8_t Transmit_Buff[BufferMaxLength];  /* 发送数据缓冲区 */
uint32_t Data_Length = 0;  							 /*  */
uint8_t Receive_Ok = 0;                  /* 接收数据完成标志位 */
uint8_t Send_Ok = 0;		                 /* 发送数据完成标志位 */

/*
  -  @函数说明:串口配置
  -  @补充:
  -  @参数:
  -  @返回值:
*/
void bsp_uart_periph_init(void)
{
	rcu_periph_clock_enable(RCU_GPIOA);	         /* 使能端口时钟 */
	rcu_periph_clock_enable(RCU_USART0);         /* 使能外设时钟 */

	gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9);	 /* 配置发送端口复用功能 */
	gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10);  /* 配置接收端口复用功能 */	

	gpio_mode_set(					GPIOA, GPIO_MODE_AF,  GPIO_PUPD_PULLUP,  GPIO_PIN_9);  /* 配置USART Tx为复用模式,带上拉 */
	gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);

	gpio_mode_set(          GPIOA, GPIO_MODE_AF,  GPIO_PUPD_PULLUP,  GPIO_PIN_10);  /* 配置USART Rx为复用模式,带上拉 */
	gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

	usart_deinit(USART0); 																		 /* 复位串口 */
	
	usart_baudrate_set(   USART0, 115200);  							     /* 设置波特率,默认为115200 */
	usart_parity_config(  USART0, USART_PM_NONE);					     /* 无校验位 */		
	usart_word_length_set(USART0, USART_WL_8BIT);  				     /* 8位数据位 */		
	usart_stop_bit_set(   USART0, USART_STB_1BIT);  			     /* 1位停止位 */		
	usart_receive_config( USART0, USART_RECEIVE_ENABLE);       /* 使能串口接收功能 */	
	usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);      /* 使能串口发送功能 */		
	usart_enable(USART0);																			 /* 使能串口 */
	
	
	usart_interrupt_enable(USART0, USART_INT_RBNE);  /* 使能USART0读数据缓冲区非空中断 */
	usart_interrupt_enable(USART0, USART_INT_IDLE);  /* 使能USART0空闲中断 */
	nvic_irq_enable(USART0_IRQn, 2, 0);
	
	/* USART interrupt configuration */
	/*	串口	 抢占优先级	子优先级	说明
		 USART0      2          0     中低优先级,用于常规通信(如调试信息)
		 USART1      2          0     同 USART0,优先级相同
		 USART2      0          0     最高优先级,可能用于关键通信(如 GPS)
		 USART5      1          0     中等优先级,可能用于次要通信。
		 其他串口    2          0     默认中低优先级 */
}

#if !defined(__MICROLIB)
//不使用微库的话就需要添加下面的函数
#if (__ARMCLIB_VERSION <= 6000000)
//如果编译器是AC5  就定义下面这个结构体
struct __FILE
{
	int handle;
};
#endif

FILE __stdout;

//定义_sys_exit()以避免使用半主机模式
void _sys_exit(int x)
{
	x = x;
}
#endif

/*
  -  @函数说明:串口重定向
  -  @补充:
  -  @参数:
  -  @返回值:
*/
int fputc(int ch, FILE *f)
{
	usart_data_transmit(USART0, (uint8_t)ch);
	while(RESET == usart_flag_get(USART0, USART_FLAG_TBE));
	return ch;
}


/*
  -  @函数说明:DMA + 串口接收 
  -  @补充:
  -  @参数:
  -  @返回值:
*/
void my_dma_init_USART_Rx(void)
{
	rcu_periph_clock_enable(RCU_DMA1);  /* 使能DMA1的时钟 */
	dma_deinit(DMA1, DMA_CH2); 				  /* DMA1复位 */
	
	dma_single_data_parameter_struct   								dma_usart_receive_init_struct;   /* 配置DMA1结构体 */
	dma_usart_receive_init_struct.direction					  = DMA_PERIPH_TO_MEMORY; 				 /* 传输方向:外设到内存 */
	dma_usart_receive_init_struct.memory0_addr			  = (uint32_t)Receive_Buff;  		   /* 内存的地址 */
	dma_usart_receive_init_struct.memory_inc 					= DMA_MEMORY_INCREASE_ENABLE; 	 /* 内存地址使用增量模式 */
	dma_usart_receive_init_struct.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;   /* 外设地址不使用增量模式 */
	dma_usart_receive_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;   			 /* 传输的数据为8位数据 */
	dma_usart_receive_init_struct.number						  = BufferMaxLength;               /* 传输的数据的个数 */
	dma_usart_receive_init_struct.periph_addr				  = (uint32_t)&USART_DATA(USART0); /* 外设的地址,这里为USART0的数据寄存器地址*/
	dma_usart_receive_init_struct.priority            = DMA_PRIORITY_ULTRA_HIGH; 			 /* 通道优先级,当多个通道都有数据,决定哪个通道优先 */
	dma_usart_receive_init_struct.circular_mode       = DMA_CIRCULAR_MODE_DISABLE;  	 /* 非循环模式 */
	dma_single_data_mode_init(DMA1, DMA_CH2, &dma_usart_receive_init_struct);          /* DMA1模式配置 */
	
	dma_channel_subperipheral_select(DMA1, DMA_CH2, DMA_SUBPERI4); 	/* 数据手册中,USART0_Rx在DMA1的外设编号为100->0000 0100 = 4 */ 
	dma_channel_enable(DMA1, DMA_CH2);  														/* 使能DMA1的通道2,USART0接收数据对应DMA1通道2/5 */
	nvic_irq_enable(DMA1_Channel2_IRQn, 2 ,0);											/* 配置DMA1通道2中断优先级分组 */
	dma_interrupt_enable(DMA1, DMA_CH2, DMA_INT_FTF);								/* 使能DMA1通道2的传输完成中断 */
	usart_dma_receive_config (USART0, USART_RECEIVE_DMA_ENABLE);		/* 使能串口的(DMA转运接收数据)功能 */
}

/*
  -  @函数说明: DMA + 串口发送 
  -  @补充:
  -  @参数:
  -  @返回值:
*/
void my_dma_init_USART_Tx(void)
{
	rcu_periph_clock_enable(RCU_DMA1);  /* 使能DMA1的时钟 */
	dma_deinit(DMA1, DMA_CH7);					/* DMA1复位 */
	
	dma_single_data_parameter_struct                   	 dma_usart_transmit_init_struct;  /* DMA1结构体 */
	dma_usart_transmit_init_struct.direction 					 = DMA_MEMORY_TO_PERIPH; 						/* 传输方向:内存到外设 */
	dma_usart_transmit_init_struct.memory0_addr        = NULL;  													/* 内存的地址 */
	dma_usart_transmit_init_struct.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;  		/* 内存地址使用增量模式 */
	dma_usart_transmit_init_struct.number              = 0;																/* 传输数据的长度,先配置为0 */
	dma_usart_transmit_init_struct.periph_inc 				 = DMA_PERIPH_INCREASE_DISABLE;  		/* 外设地址不使用增量模式 */
	dma_usart_transmit_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT; 			 		/* 传输的数据为8位数据 */
	dma_usart_transmit_init_struct.periph_addr         = (uint32_t)&USART_DATA(USART0);  	/* 外设的地址,这里为USART0的数据寄存器地址*/
	dma_usart_transmit_init_struct.priority            = DMA_PRIORITY_ULTRA_HIGH; 				/* 通道优先级,当多个通道都有数据,决定哪个通道优先 */
	dma_usart_transmit_init_struct.circular_mode       = DMA_CIRCULAR_MODE_DISABLE;  			/* 非循环模式 */
	dma_single_data_mode_init(DMA1, DMA_CH7, &dma_usart_transmit_init_struct);  					/* DMA1模式配置 */
	
	dma_channel_subperipheral_select(DMA1, DMA_CH7, DMA_SUBPERI4);  /* 数据手册中,USART0_Rx在DMA1的外设编号为100->0000 0100 = 4 */ 
	usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);   /* 使能串口发送数据的DMA传输功能 */
	nvic_irq_enable(DMA1_Channel7_IRQn, 2 ,0);										  /* 配置DMA1通道7中断优先级分组 */
	dma_interrupt_enable(DMA1, DMA_CH7, DMA_INT_FTF|DMA_INT_TAE);	  /* 使能DMA1通道7的传输完成中断(必要)与传输错误中断(非必要) */
}

/*
  -  @函数说明:串口Tx使用DMA发送数据
  -  @补充:
  -  @参数:发送数据的数组,要发送的数据的个数
  -  @返回值:
*/
void usart_tx_data_dma(uint8_t* data_buff, uint8_t length)
{
	while(usart_flag_get(USART0, USART_FLAG_TC) == RESET);  /* 如果上一次串口数据发送完成完成 */
	memset(data_buff, 0, sizeof(Receive_Buff) / sizeof(Receive_Buff[0]) );  /* 清空数组 */
	printf("\nSend_Data_Ok");
	if(length > BufferMaxLength)	length = BufferMaxLength;  /* 防止长度越界 */
	memcpy(Transmit_Buff, data_buff, length); 			/* 复制接收缓冲区的数据到发送缓冲区 */
	
	dma_channel_disable(DMA1, DMA_CH7);  /* 先失能DMA1通道 */  																	
	dma_memory_address_config(DMA1, DMA_CH7, DMA_MEMORY_0, (uint32_t)Transmit_Buff);  /* 配置DMA转运的内存地址为发送缓冲区数组 */
	dma_transfer_number_config(DMA1, DMA_CH7, length+1);  														/* 设置本次DMA转运的数据数量 */
	dma_channel_enable(DMA1, DMA_CH7); 																								/* 开启DMA通道 */
}



/*
  -  @函数说明:DMA通道2中断服务函数
  -  @补充:DMA转运串口收到数据到内存完成后
  -  @参数:none
  -  @返回值:none
*/
//void DMA1_Channel2_IRQHandler(void)
//{
//	if(dma_interrupt_flag_get(DMA1, DMA_CH2, DMA_INT_FLAG_FTF) == SET)
//	{
//		dma_interrupt_flag_clear(DMA1, DMA_CH2, DMA_INT_FLAG_FTF);
//		printf("DMA Move Data Ok\n");
//	}
//}

/*
	-  @函数说明:DMA通道7中断服务函数
  -  @补充:用于DMA发送串口数据完成后
  -  @参数:none
  -  @返回值:none
*/
//void DMA1_Channel7_IRQHandler(void)
//{
//	if(dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INT_FLAG_FTF) == SET)
//	{
//		printf("\nDMA Send Data Ok");
//		dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INT_FLAG_FTF); 
//	}
//	if(dma_interrupt_flag_get(DMA1, DMA_CH7, DMA_INT_FLAG_TAE)) 
//	{
//		printf("\nDMA Transfer Error");
//		dma_interrupt_flag_clear(DMA1, DMA_CH7, DMA_INT_FLAG_TAE);
//  }
//}
